﻿using ArtMath.Attribute;
using ArtMath.Component.CoordinateSystem.Converter;
using ArtMath.Component.Line;
using ArtMath.Component.Point;
using ArtMath.Core.Data;
using ArtMath.Core.Helper;
using ArtMath.Data;
using ArtMath.Editor;
using ArtMath.Resource;
using ArtMath.Setting;
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;

namespace ArtMath.Component.CoordinateSystem
{
    /// <summary>
    /// 直角坐标系坐标轴基类
    /// </summary>
    [Serializable]
    public abstract class RectangularCoordinateAxisBase : PointSlopeLineBase, IAxis
    {
        AxisTextLocation axistxtloc = AxisTextLocation.Below;
        PadStringX scale, unit;
        protected double interval = 1;
        double min, max;
        bool showRuler = true, showNum = true, showGrid = true;
        protected ColorX rulerColor, textColor, gridColor;
        protected RectangularCoordinate linkedRC;
        public event Action MinValueChanged, MaxValueChanged;
        public RectangularCoordinateAxisBase(SketchPad pad, string name, ToolTypeName toolType, bool addToList = true) : base(pad, name, toolType, addToList)
        {
            InPoints = new PointBase[1];
            rulerColor = new ColorX(Pad, Settings.Instance.AxisRulerColor);
            textColor = new ColorX(Pad, Settings.Instance.AxisTextColor);
            gridColor = new ColorX(Pad, Settings.Instance.AxisGridColor);
            Scale = new PadStringX(Pad, Settings.Instance.AxisScale);
            Unit = new PadStringX(Pad, "1");
            linkedRC = Pad.Coordinate as RectangularCoordinate;
        }
        protected virtual void Scale_ParametersValueChanged(DocStringX sender, ParametersValueChangedEventArgs e)
        {
            if (Scale.Value > 0)
            {
                interval = Utility.ConvertAxisInterval(Scale.Value);
            }
        }
        protected virtual void Scale_ExpressionSet(StringX sender, ExpressionSetEventArgs e)
        {
            if (Scale.Value > 0)
            {
                interval = Utility.ConvertAxisInterval(Scale.Value);
            }
            else
            {
                Pad.ShowMessage(Resources.JoinLocalizedString("AxisScale", "MustBePositive"), MessageType.Error);
                Scale.SetExpression(e.OldExpression, false);
            }
        }
        void Unit_ParametersValueChanged(DocStringX sender, ParametersValueChangedEventArgs e)
        {
            if (Unit.Value > 0)
            {
                Pad.Coordinate.CoordinateChanged(PointsRelocationReason.UnitChanged);
            }
        }
        void Unit_ExpressionSet(StringX sender, ExpressionSetEventArgs e)
        {
            if (Unit.Value > 0)
            {
                Pad.Coordinate.CoordinateChanged(PointsRelocationReason.UnitChanged);
            }
            else
            {
                Pad.ShowMessage(Resources.JoinLocalizedString("Unit", "MustBePositive"), MessageType.Error);
                Unit.SetExpression(e.OldExpression, false);
            }
        }
        [Browsable(false)]
        public override AngleStringX RotateAngle
        {
            get
            {
                return base.RotateAngle;
            }

            set
            {
                base.RotateAngle = value;
            }
        }
        [Browsable(false)]
        public override RPointS RotateCenter
        {
            get
            {
                return base.RotateCenter;
            }

            set
            {
                base.RotateCenter = value;
            }
        }
        [Browsable(false)]
        public double Max
        {
            get { return max; }
            protected set
            {
                if (max == value) return;
                max = value;
                MaxValueChanged?.Invoke();
            }
        }
        [Browsable(false)]
        public double Min
        {
            get { return min; }
            protected set
            {
                if (min == value) return;
                min = value;
                MinValueChanged?.Invoke();
            }
        }
        [MultilingualCategory("Appearance"), MultilingualDisplayName(null, "GraduationText", "Location"), TypeConverter(typeof(AxisTextLocationConverter))]
        public AxisTextLocation GraduationTextLocation
        {
            get { return axistxtloc; }
            set
            {
                axistxtloc = value;
                Pad.Canvas.Invalidate();
            }
        }
        [MultilingualCategory("Preference"), MultilingualDisplayName("AxisScale"), DefaultValue(typeof(PadStringX), "50"), Editor(typeof(SliderEditor), typeof(UITypeEditor))]
        public PadStringX Scale
        {
            get { return scale; }
            set
            {
                if (scale is object)
                {
                    scale.ParametersValueChanged -= Scale_ParametersValueChanged;
                    scale.ExpressionSet -= Scale_ExpressionSet;
                }
                scale = value;
                if (scale is object)
                {
                    scale.ParametersValueChanged += Scale_ParametersValueChanged;
                    scale.ExpressionSet += Scale_ExpressionSet;
                }
            }
        }
        [MultilingualCategory("Preference"), MultilingualDisplayName("Unit"), DefaultValue(typeof(PadStringX), "1"), TypeConverter(typeof(AxisUnitConverter))]
        public PadStringX Unit
        {
            get { return unit; }
            set
            {
                if (unit is object)
                {
                    unit.ParametersValueChanged -= Unit_ParametersValueChanged;
                    unit.ExpressionSet -= Unit_ExpressionSet;
                }
                unit = value;
                if (unit is object)
                {
                    unit.ParametersValueChanged += Unit_ParametersValueChanged;
                    unit.ExpressionSet += Unit_ExpressionSet;
                }
            }
        }
        [MultilingualCategory("View"), MultilingualDisplayName(null, "Show", "Grid"), TypeConverter(typeof(ArtMath.Converter.BooleanConverter)), DefaultValue(typeof(bool), "True")]
        public bool ShowGrid
        {
            get { return showGrid; }
            set
            {
                showGrid = value;
                Pad.Canvas.Invalidate();
            }
        }
        [MultilingualCategory("View"), MultilingualDisplayName(null, "Show", "Graduation"), TypeConverter(typeof(ArtMath.Converter.BooleanConverter)), DefaultValue(typeof(bool), "True")]
        public bool ShowGraduation
        {
            get { return showRuler; }
            set
            {
                showRuler = value;
                Pad.Canvas.Invalidate();
            }
        }
        [MultilingualCategory("View"), MultilingualDisplayName(null, "Show", "GraduationText"), TypeConverter(typeof(ArtMath.Converter.BooleanConverter)), DefaultValue(typeof(bool), "True")]
        public bool ShowGraduationText
        {
            get { return showNum; }
            set
            {
                showNum = value;
                Pad.Canvas.Invalidate();
            }
        }
        [MultilingualCategory("Appearance"), MultilingualDisplayName(null, "GraduationText", "Color"), DefaultValue(typeof(Color), "Black")]
        public Color GraduationTextColor
        {
            get { return textColor.Color; }
            set { textColor.Color = value; }
        }
        [MultilingualCategory("Appearance"), MultilingualDisplayName(null, "Graduation", "Color"), DefaultValue(typeof(Color), "237, 125, 49")]
        public Color GraduationColor
        {
            get { return rulerColor.Color; }
            set { rulerColor.Color = value; }
        }
        [MultilingualCategory("Appearance"), MultilingualDisplayName(null, "Grid", "Color"), DefaultValue(typeof(Color), "211, 211, 211")]
        public Color GridColor
        {
            get { return gridColor.Color; }
            set { gridColor.Color = value; }
        }
        protected override Pen LinePen
        {
            get
            {
                Pen P = base.LinePen;
                P.CustomEndCap = new AdjustableArrowCap(4, 4, true);
                return P;
            }
        }
        public override void CreateComponents()
        {
            ske.Location = new PointD(0, 0);
            pske.Location = linkedRC.XYToPxy(Location);
            base.CreateComponents();
        }
        protected string FormatRuler(double value)
        {
            string res;
            if (value.IsInteger())
            {
                res = value.ToString();
            }
            else
            {
                res = value.ToString("F" + interval.AfterPointCount());
            }
            return Utility.DecoratePolynomial(Utility.StandardizePolynomial($"{res}*({Unit.DirectExpression})"));
        }
        public override void SetFromString(string exp)
        {
            string[] tokens = exp.Split(';', '；');
            if (tokens.Length == 2)
            {
                Scale.SetFromString(tokens[0]);
                Unit.SetFromString(tokens[1]);
            }
        }
    }
}
